package cn.lg.soar.boot.client.api;

import cn.lg.soar.boot.client.api.exception.OverdueTokenException;
import cn.lg.soar.boot.client.api.exception.UnTokenException;
import cn.lg.soar.boot.client.api.token.ClientToken;
import cn.lg.soar.boot.client.entity.Applicant;
import cn.lg.soar.boot.client.entity.ClientUser;
import cn.lg.soar.boot.client.entity.vo.ClientUserVo;
import cn.lg.soar.boot.client.service.ApplicantService;
import cn.lg.soar.boot.client.service.ClientApiService;
import cn.lg.soar.boot.client.service.ClientUserService;
import cn.lg.soar.boot.fc.entity.Contract;
import cn.lg.soar.boot.fc.entity.FormItem;
import cn.lg.soar.boot.fc.entity.vo.*;
import cn.lg.soar.boot.fc.params.RoomParams;
import cn.lg.soar.boot.fc.service.RoomService;
import cn.lg.soar.boot.fc.service.TenancyRoomService;
import cn.lg.soar.common.model.HttpResult;
import cn.lg.soar.common.model.PageQuery;
import cn.lg.soar.common.model.PageResult;
import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.database.query.QueryParams;
import cn.lg.soar.general.api.model.FileVO;
import cn.lg.soar.general.entity.FileMetadata;
import cn.lg.soar.general.service.FileUploadService;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 客户端API接口
 *
 * @author helios
 * @date 2020-11-28
 */

@Api(tags={"客户端API"})
@RestController
@RequestMapping("/api/client")
public class ClientAPI {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    /** 用户信息服务 */
    @Autowired private ClientUserService userService;
    /** api服务 */
    @Autowired private ClientApiService apiService;
    @Autowired
    private RoomService roomService;
    @Autowired
    private FileUploadService fileUploadService;
    @Autowired
    private ApplicantService applicantService;

    /**
     * 用户密码登录
     */
    @ApiOperation(value="用户密码登录", notes="进行用户登录,成功后返回用户信息并更新访问令牌")
    @RequestMapping(value={"/signin"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name="account", value="用户账号", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataTypeClass = String.class, paramType="query"),
    })
    public HttpResult<Object> signin(String account, String password) {
        logger.info("[req]:用户密码登录(ClientAPI->signin)");
        logger.debug("\t->account:{}", account);
        logger.debug("\t->password:{}", "******");

        return apiService.signin(account, password);
    }

    /**
     * 获取用户信息
     */
    @ClientToken
    @ApiOperation(value="获取用户信息", notes="获取用户信息")
    @RequestMapping(value={"/userInfo"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
    })
    public HttpResult<ClientUserVo> userInfo(@RequestHeader String accesstoken) {
        logger.info("[req]:获取用户信息(ClientAPI->userInfo)");

        return apiService.userInfo(accesstoken);
    }

    /**
     * 获取房源列表
     */
    @ClientToken
    @ApiOperation(value="获取房源列表", notes="获取房源列表")
    @RequestMapping(value={"/roomList"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "pageNo", value = "页码", required = true, dataTypeClass = Integer.class, paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, dataTypeClass = Integer.class, paramType = "query"),
    })
    public HttpResult<PageResult<RoomVo>> roomList(@RequestHeader String accesstoken, PageQuery pageQuery, QueryParams params, RoomParams roomParams) {
        logger.info("[req]:获取房源列表(ClientAPI->roomList)");

        return HttpResult.data(roomService.queryResultVo(pageQuery, params, roomParams));
    }

    /**
     * 获取房源详情
     */
    @ClientToken
    @ApiOperation(value="获取房源详情", notes="获取房源详情")
    @RequestMapping(value={"/roomInfo"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "roomId", value = "房间ID", required = true, dataTypeClass = Long.class, paramType = "query"),
    })
    public HttpResult<RoomVo> roomInfo(@RequestHeader String accesstoken, Long roomId) {
        logger.info("[req]:获取房源详情(ClientAPI->roomInfo)");

        return HttpResult.data(roomService.getVoData(roomId));
    }

    /**
     * 获取我的房源/历史房源
     */
    @ClientToken
    @ApiOperation(value="获取我的房源/历史房源", notes="获取我的房源/历史房源")
    @RequestMapping(value={"/housingList"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "pageNo", value = "页码", required = true, dataTypeClass = Integer.class, paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, dataTypeClass = Integer.class, paramType = "query"),
            @ApiImplicitParam(name = "housingType", value = "查询类型(0-我的房源 1-历史房源)", required = true, dataTypeClass = Integer.class, paramType = "query"),
    })
    public HttpResult<PageResult<TenancyRoomVo>> housingList(@RequestHeader String accesstoken, PageQuery pageQuery, Integer housingType) {
        logger.info("[req]:获取我的房源/历史房源(ClientAPI->roomList)");

        return apiService.housingList(pageQuery,accesstoken,housingType);
    }

    /**
     * 获取房源详情
     */
    @ClientToken
    @ApiOperation(value="获取房源详情", notes="获取房源详情")
    @RequestMapping(value={"/tenancyRoomInfo"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "tenancyRoomId", value = "租房ID", required = true, dataTypeClass = Long.class, paramType = "query"),
    })
    public HttpResult<TenancyRoomVo> tenancyRoomInfo(@RequestHeader String accesstoken, Long tenancyRoomId) {
        logger.info("[req]:获取房源详情(ClientAPI->tenancyRoomInfo)");

        return apiService.tenancyRoomInfo(tenancyRoomId);
    }

    /**
     * 获取表单
     */
    @ClientToken
    @ApiOperation(value="获取租房表单/用户表单", notes="获取租房表单/用户表单")
    @RequestMapping(value={"/formItem"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "visibleRange", value = "可见范围(0-用户表单 1-租房表单)", required = true, dataTypeClass = Integer.class, paramType = "query"),
    })
    public HttpResult<List<FormItem>> formItem(@RequestHeader String accesstoken, Integer visibleRange) {
        logger.info("[req]:获取租房表单/用户表单(ClientAPI->formItem)");

        return apiService.formItem(visibleRange);
    }

    /**
     * 申请租房
     */
    @ClientToken
    @ApiOperation(value="申请租房", notes="申请租房")
    @RequestMapping(value={"/applyRoom"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "applicantId", value = "申请人ID", required = true, dataTypeClass = Long.class, paramType = "query"),
            @ApiImplicitParam(name = "collectId", value = "表单收集ID", required = true, dataTypeClass = Long.class, paramType = "query"),
            @ApiImplicitParam(name = "roomId", value = "房间ID", required = true, dataTypeClass = Long.class, paramType = "query"),
            @ApiImplicitParam(name = "processData", value = "提交表单信息(json字符串)", required = true, dataTypeClass = String.class, paramType = "query"),
    })
    public HttpResult<Void> applyRoom(@RequestHeader String accesstoken,Long applicantId,Long collectId,Long roomId,String processData) {
        logger.info("[req]:申请租房(ClientAPI->applyRoom)");

        return apiService.applyRoom(accesstoken,applicantId,collectId,roomId,processData);
    }

    /**
     * 获取用户房源记录
     */
    @ClientToken
    @ApiOperation(value="获取用户房源记录", notes="获取用户房源记录")
    @RequestMapping(value={"/housingRecord"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "pageNo", value = "页码", required = true, dataTypeClass = Integer.class, paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, dataTypeClass = Integer.class, paramType = "query"),
    })
    public HttpResult<PageResult<HousingRecordVo>> housingRecord(@RequestHeader String accesstoken, PageQuery pageQuery) {
        logger.info("[req]:获取用户房源记录(ClientAPI->housingRecord)");

        return apiService.housingRecord(pageQuery,accesstoken);
    }

    /**
     * 申请续租
     */
    @ClientToken
    @ApiOperation(value="申请续租", notes="申请续租")
    @RequestMapping(value={"/continueApply"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "tenancyId", value = "租房ID", required = true, dataTypeClass = Long.class, paramType = "query"),
    })
    public HttpResult<Void> continueApply(@RequestHeader String accesstoken, Long tenancyId) {
        logger.info("[req]:申请续租(ClientAPI->continueApply)");

        return apiService.continueApply(accesstoken,tenancyId);
    }

    /**
     * 获取用户续租记录
     */
    @ClientToken
    @ApiOperation(value="获取用户续租记录", notes="获取用户续租记录")
    @RequestMapping(value={"/continueRecord"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "pageNo", value = "页码", required = true, dataTypeClass = Integer.class, paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, dataTypeClass = Integer.class, paramType = "query"),
    })
    public HttpResult<PageResult<HousingRecordVo>> continueRecord(@RequestHeader String accesstoken, PageQuery pageQuery) {
        logger.info("[req]:获取用户续租记录(ClientAPI->continueRecord)");

        return apiService.continueRecord(pageQuery,accesstoken);
    }

    /**
     * 申请退租
     */
    @ClientToken
    @ApiOperation(value="申请退租", notes="申请退租")
    @RequestMapping(value={"/exitTenancyApply"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "tenancyId", value = "租房ID", required = true, dataTypeClass = Long.class, paramType = "query"),
    })
    public HttpResult<Void> exitTenancyApply(@RequestHeader String accesstoken, Long tenancyId) {
        logger.info("[req]:申请退租(ClientAPI->exitTenancyApply)");

        return apiService.exitTenancyApply(accesstoken,tenancyId);
    }

    /**
     * 获取用户退租记录
     */
    @ClientToken
    @ApiOperation(value="获取用户退租记录", notes="获取用户退租记录")
    @RequestMapping(value={"/exitTenancyRecord"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "pageNo", value = "页码", required = true, dataTypeClass = Integer.class, paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, dataTypeClass = Integer.class, paramType = "query"),
    })
    public HttpResult<PageResult<HousingRecordVo>> exitTenancyRecord(@RequestHeader String accesstoken, PageQuery pageQuery) {
        logger.info("[req]:获取用户退租记录(ClientAPI->exitTenancyRecord)");

        return apiService.exitTenancyRecord(pageQuery,accesstoken);
    }

    /**
     * 申请报修
     */
    @ClientToken
    @ApiOperation(value="申请报修", notes="申请报修")
    @RequestMapping(value={"/repair"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "tenancyRoomId", value = "租房ID", required = true, dataTypeClass = Long.class, paramType = "query"),
            @ApiImplicitParam(name = "repairerName", value = "报修人", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "repairerPhone", value = "报修人联系电话", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "facilities", value = "报修设施", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "repairDescribe", value = "报修描述", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "img", value = "报修图片", required = false, dataTypeClass = String.class, paramType = "query"),
    })
    public HttpResult<Void> repair(@RequestHeader String accesstoken, Long tenancyRoomId,String repairerName,String repairerPhone,
                                   String facilities,String repairDescribe,String img) {
        logger.info("[req]:申请报修(ClientAPI->repair)");

        RepairSubmitVo repairSubmitVo = new RepairSubmitVo();
        repairSubmitVo.setTenancyRoomId(tenancyRoomId);
        repairSubmitVo.setRepairerName(repairerName);
        repairSubmitVo.setRepairerPhone(repairerPhone);
        repairSubmitVo.setFacilities(facilities);
        repairSubmitVo.setRepairDescribe(repairDescribe);
        repairSubmitVo.setImg(img);
        return apiService.repair(accesstoken,repairSubmitVo);
    }

    /**
     * 获取用户报修记录
     */
    @ClientToken
    @ApiOperation(value="获取用户报修记录", notes="获取用户报修记录")
    @RequestMapping(value={"/repairRecord"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "pageNo", value = "页码", required = true, dataTypeClass = Integer.class, paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, dataTypeClass = Integer.class, paramType = "query"),
    })
    public HttpResult<PageResult<RepairVo>> repairRecord(@RequestHeader String accesstoken, PageQuery pageQuery) {
        logger.info("[req]:获取用户报修记录(ClientAPI->repairRecord)");

        return apiService.repairRecord(pageQuery,accesstoken);
    }

    @ClientToken
    @ApiOperation("客户端上传")
    @PostMapping(path = "upload", name = "客户端上传")
    public HttpResult<List<FileVO>> upload(@ApiParam @RequestParam("files") MultipartFile[] files) {
//        if (DataUtil.isValuable(bucketName)) {
//            List<FileMetadata> metadataList = fileUploadService.upload(bucketName, files);
//            return HttpResult.data(fileUploadService.toVos(metadataList));
//        }
        List<FileMetadata> metadataList = fileUploadService.upload(files);
        return HttpResult.data(fileUploadService.toVos(metadataList));
    }

    /**
     * 获取待签合同详情
     */
    @ClientToken
    @ApiOperation(value="获取待签合同详情", notes="获取待签合同详情")
    @RequestMapping(value={"/contractInfo"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "tenancyRoomId", value = "租房ID", required = true, dataTypeClass = Long.class, paramType = "query"),
    })
    public HttpResult<Contract> contractInfo(@RequestHeader String accesstoken, Long tenancyRoomId) {
        logger.info("[req]:获取待签合同详情(ClientAPI->contractInfo)");

        return apiService.contractInfo(accesstoken,tenancyRoomId);
    }

    /**
     * 合同签订
     */
    @ClientToken
    @ApiOperation(value="合同签订", notes="合同签订")
    @RequestMapping(value={"/contractSign"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "contractId", value = "合同ID", required = true, dataTypeClass = Long.class, paramType = "query"),
            @ApiImplicitParam(name = "signUrl", value = "签订上传后URL", required = true, dataTypeClass = String.class, paramType = "query"),
    })
    public HttpResult<Void> contractSign(@RequestHeader String accesstoken, Long contractId,String signUrl) {
        logger.info("[req]:合同签订(ClientAPI->contractSign)");

        return apiService.contractSign(accesstoken,contractId,signUrl);
    }

    /**
     * 申请人提交用户基础信息
     */
    @ClientToken
    @ApiOperation(value="申请人提交用户基础信息", notes="申请人提交用户基础信息")
    @RequestMapping(value={"/applyApplicant"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
            @ApiImplicitParam(name = "collectId", value = "表单ID", required = true, dataTypeClass = Long.class, paramType = "query"),
            @ApiImplicitParam(name = "formResultId", value = "表单提交ID", required = false, dataTypeClass = Long.class, paramType = "query"),
            @ApiImplicitParam(name = "name", value = "姓名", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "phone", value = "联系电话", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "userLink", value = "与用户关系(0-本人 1-配偶 2-父母 3-子女 4-朋友 5-其他)", required = true, dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "processData", value = "提交表单信息(json字符串)", required = true, dataTypeClass = String.class, paramType = "query"),
    })
    public HttpResult<Void> applyApplicant(@RequestHeader String accesstoken,Long collectId,Long formResultId,String name,
                                           String phone,Integer userLink,String processData) {
        logger.info("[req]:申请人提交用户基础信息(ClientAPI->applyApplicant)");

        return apiService.applyApplicant(accesstoken,collectId,formResultId,name,phone,userLink,processData);
    }
    
    /**
     * 刷新token
     */
    @ApiOperation(value="刷新token", notes="使用旧token获取新token")
    @RequestMapping(value={"/refreshToken"}, method={RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "accesstoken", value = "访问令牌", required = true, dataTypeClass = String.class, paramType = "header"),
    })
    public HttpResult<Object> refreshToken(@RequestHeader String accesstoken) {
        logger.info("[req]:刷新token(ClientAPI->refreshToken)");

        // 如果还是没有token,则抛异常
        if (StringUtils.isBlank(accesstoken)) {
            throw new UnTokenException("请求必须携带令牌");
        }

        ClientUser user = userService.selectByToken(accesstoken);
        if (user == null) {
            logger.error("令牌信息不存在");
            throw new OverdueTokenException("令牌信息不存在");
        }

        return apiService.refreshToken(accesstoken);
    }
}
